#==================================================
#	Skill
#==================================================
#  非持续性技能的基类
# * 扩展脚本时重写 _cast 方法进行添加施放效果
# * 连接此节点的信号进行不同阶段功能的施放
#==================================================
# @path: res://addons/function_tree/src/base/function/skills/Skill.gd
# @datetime: 2021-12-12 11:52:07
#==================================================
extends "../Function.gd"


## 准备执行（执行技能前摇）
signal ready_execute
## 执行了技能
signal executed
## 技能执行完成(后摇结束)
signal execute_finished
## 技能状态刷新了 (冷却时间结束了)
signal status_refreshed
## 技能停止
signal stopped


## 注册这个到全局 Function 数据中
# 让节点可通过 get_function(节点名) 获取到这个节点
export var register : bool = true
## 技能前摇（准备技能的时间）
export var before_shake : float = 0.0 setget set_before_shake
## 技能后摇（结束技能的时间）
export var after_shake : float = 0.0 setget set_after_shake
## 施放间隔时间
export var interval : float = 1.0 setget set_interval


## 刷新间隔时间计时器
var _refresh_timer := Timer.new()

var _skill_timer := SkillTimer.new(self)
var _state := SkillStatus.new()



#==================================================
#   Set/Get
#==================================================
##  技能是否可用 
## @return  
func is_enabled() -> bool:
	return (
		.is_enabled()
		&& _state.is_can_cast()
		&& _refresh_timer.is_stopped()
	)

func set_before_shake(value: float) -> void:
	before_shake = value
	_skill_timer.before_time = value

func set_after_shake(value: float) -> void:
	after_shake = value
	_skill_timer.after_time = value

func set_interval(value: float) -> void:
	interval = value
	if _refresh_timer == null:
		yield(self, "tree_entered")
	_refresh_timer.wait_time = value

##  可攻击的剩余时间
## @return  
func attack_time_left() -> float:
	return _refresh_timer.time_left



#==================================================
#   自定义方法
#==================================================
#(override)
func _init_data():
	._init_data()
	if register:
		register_to_function(self.name)


#(override)
func _init_node():
	._init_node()
	
	_skill_timer.set_before(before_shake, "_execute")
	_skill_timer.set_after(after_shake, "_execute_finish")
	
	# 间隔时间结束，则调用 refresh() 方法
	_refresh_timer.one_shot = true
	_refresh_timer.autostart = false
	_refresh_timer.wait_time = max(0.02, interval)
	_refresh_timer.connect("timeout", self, "refresh")
	self.add_child(_refresh_timer)



#==================================================
#   Skill 方法
#==================================================
##  开始执行技能
## @_data  技能数据
## @return  返回是否可以执行
func control(_data) -> bool:
	if is_enabled():
		emit_signal("ready_execute")
		_state.ready()
		_skill_timer.start()
		return true
	
	# 没有执行成功
	return false


##  执行（开始准备执行）
func _execute() -> void:
	# 不能施放时施放
	if _state.is_casting():
		return
	# 开始间隔倒计时
	_refresh_timer.start(interval)
	_state.cast()
	# 开始执行具体功能
	_cast()
	# 施放后
	_executed()


##  施放技能（实施技能效果）
func _cast() -> void:
	pass


##  功能施放后
## （这个是在技能发出瞬间之后进行处理的）
func _executed() -> void:
	_state.executed()
	_skill_timer.executed()
	emit_signal("executed")


##  执行完成
func _execute_finish() -> void:
	_state.executed()
	emit_signal("execute_finished")


## 停止
func stop() -> bool:
	# 还没开始执行就停止时
	if _state.is_ready():
		_state.refreshed()
	# 如果不是停止状态则执行
	if not _state.get_value() in [
		SkillStatus.Type.CAN_CAST, 
		SkillStatus.Type.FINISHED
	]:
		_state.executed()
		_skill_timer.stop()
		emit_signal("stopped")
		return true
	return false


##  技能刷新
func refresh() -> void:
	_refresh_timer.stop()
	_state.refreshed()
	emit_signal("status_refreshed")



#==================================================
#   施放动作计时器
#==================================================
class SkillTimer:
	const MIN_TIME = 0.02
	
	var host : Node
	var before := Timer.new()
	var after := Timer.new()
	
	var before_time : float = 0.0 
	var after_time : float = 0.0 
	
	func _init(host: Node):
		self.host = host
	
	func set_before(wait_time: float, method: String, binds: Array = []):
		before_time = wait_time
		before.wait_time =  max(MIN_TIME, wait_time)
		before.one_shot = true
		before.autostart = false
		before.connect("timeout", host, method, binds)
		if not host.is_inside_tree():
			yield(host, "tree_entered")
		host.add_child(before)
	
	func set_after(wait_time: float, method: String, binds: Array = []):
		after_time = wait_time
		after.wait_time = max(MIN_TIME, wait_time)
		after.one_shot = true
		after.autostart = false
		after.connect("timeout", host, method, binds)
		if not host.is_inside_tree():
			yield(host, "tree_entered")
		host.add_child(after)
	
	func start():
		# （必须加计时器时间，因为在准备施放时要至少有一帧的等待时间
		# 没有这个时间则会有方法执行顺序的问题）
		# 前摇动作时间
		before.start(max(before_time, MIN_TIME))
	
	func executed():
		# 后摇动作时间
		after.start(max(after_time, MIN_TIME))
	
	func stop():
		before.stop()
		after.stop()



#==================================================
#   技能状态
#==================================================
class SkillStatus:
	
	enum Type {
		CAN_CAST,	# 可使用
		READY,		# 开始准备施放
		CASTING,	# 施放中
		FINISHED,	# 施放结束
	}
	
	var _value = Type.CAN_CAST
	
	func get_value():
		return _value
	
	func is_casting():
		return _value == Type.CASTING
	
	func is_ready():
		return _value == Type.READY
	
	# 是否可以施放
	func is_can_cast():
		return _value == Type.CAN_CAST
	
	# 准备施放
	func ready():
		switch_state(Type.READY)
	
	# 施放中
	func cast():
		switch_state(Type.CASTING)
	
	# 施放后
	func executed():
		if _value != Type.CAN_CAST:
			switch_state(Type.FINISHED)
	
	# 刷新（刷新后可施放）
	func refreshed():
		switch_state(Type.CAN_CAST)
	
	## 切换状态
	func switch_state(state):
		_value = state
#		if _value != state:
#			_value = state
	
	

